/******************************************************************************/
//	Direct3DManager.cpp	-	A Manager to handle all Direct3D needs.
//
//	Author:		Russell Klinkerman
//	Created:	02.24.2004
/******************************************************************************/
//	Updated:	12.10.2004
/******************************************************************************/

#include "Direct3DManager.h"

CDirect3DManager d3dManager;

#include "AppCore.h"

bool	CDirect3DManager::Init()
{
	// Get the Interface to Direct3D
	if(!(pDirect3DInterface	=	Direct3DCreate9(D3D_SDK_VERSION)))
		return false;	//	If Failed.

	/******************************************/
	// Setup the D3D Presentation Parameters
	memset(&D3DPresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));	// Wipe Structure's Memory

	bool bWindowed = !appCore.GetFullScreen();

	// Windowed with fastest swap effect and default bb format.
	D3DPresentParams.Windowed				=	bWindowed;
	D3DPresentParams.hDeviceWindow			=	appCore.GetWnd();
	D3DPresentParams.SwapEffect				=	D3DSWAPEFFECT_DISCARD;
	D3DPresentParams.BackBufferFormat		=	bWindowed ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8;;
	D3DPresentParams.BackBufferCount		=	1;
	D3DPresentParams.BackBufferWidth		=	appCore.GetWndWidth();
	D3DPresentParams.BackBufferHeight		=	appCore.GetWndHeight();
	D3DPresentParams.PresentationInterval	=	D3DPRESENT_INTERVAL_IMMEDIATE;	// DO NOT VSYNC!!

	HRESULT	hr	=	0;	// Used for error-checking.

	// Create the Direct3D Device
	if( FAILED(hr = pDirect3DInterface->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, appCore.GetWnd(),
		D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3DPresentParams, &pDirect3DDevice)))
		{ POSTERR(hr);	return false; }

	/***	Essential initialization is complete	***/

	// Get Adapter display settings
	pDirect3DDevice->GetDisplayMode(0, &displaySettings);
    
	// Turn off culling and lighting
	pDirect3DDevice->SetRenderState( D3DRS_CULLMODE,		D3DCULL_CW );
    pDirect3DDevice->SetRenderState( D3DRS_SHADEMODE,		D3DSHADE_GOURAUD );
    pDirect3DDevice->SetRenderState( D3DRS_LIGHTING,		true );
    pDirect3DDevice->SetRenderState( D3DRS_SPECULARENABLE,	true );
    pDirect3DDevice->SetRenderState( D3DRS_AMBIENT,			0xff7f7f7f ); //0x00000000
    pDirect3DDevice->SetRenderState( D3DRS_ZENABLE,			true );

	/******************************************/
	// Setup the View and Projection Matrices

	D3DXMatrixLookAtRH(&viewMatrix,	&D3DXVECTOR3(0.0f, 1.0f, 3.0f),     // cam position
									&D3DXVECTOR3(0.0f, 0.0f, 0.0f),     // look at point
									&D3DXVECTOR3(0.0f, 1.0f, 0.0f) );   // up direction


	if( FAILED( hr = pDirect3DDevice->SetTransform( D3DTS_VIEW, &viewMatrix ) ) )
		{ POSTERR(hr);	return false; }

	// Set the Projection Matrix
	SetProjection(DXMP_PERSPECTIVE);

	/******************************************/
	// Setup fonts

	hr = D3DXCreateFont(	pDirect3DDevice,	// The D3D Device
							16,					// Font Height
							0,					// Font Width
							FW_BOLD,			// Font Weight
							0,					// Miplevels
							0,					// Italic Flag (1 = Italics)
							DEFAULT_CHARSET,	// Character Set
							OUT_DEFAULT_PRECIS,	// Precision
							DEFAULT_QUALITY,	// Quality (Only for rastor fonts, TT unaffected)
							DEFAULT_PITCH |
								FF_DONTCARE,	// Pitch & Family
							"Arial",			// Typeface
							&pFont				// Font Interface
						);

	if(FAILED(hr)) return false;

	/******************************************/
	// Setup Sprite Interface

	if(FAILED(hr = D3DXCreateSprite(pDirect3DDevice, &pSpriteInterface)))
		return false;

	pCurrentSpriteMatrix = NULL;


	return true;
}

void	CDirect3DManager::SetProjection(DXM_PROJECTION eProjection, float	fNearPlane, float fFarPlane, float fFieldOfView)
{
	// Switch based on Projection Choice
	switch(eProjection)
	{
		case DXMP_PERSPECTIVE:
		{
			// Setup perspective projection matrix.
			D3DXMatrixPerspectiveFovRH(&projectionMatrix, fFieldOfView, appCore.GetWndWidth() / (float)appCore.GetWndHeight(), fNearPlane, fFarPlane);
		}
		break;
		
		case DXMP_ORTHO:
		{
			// Setup orthogonal projection matrix.
			D3DXMatrixOrthoRH(&projectionMatrix, (float)appCore.GetWndWidth(), (float)appCore.GetWndHeight(), fNearPlane, fFarPlane);
		}
		break;
	};

	HRESULT	hr	=	0;	// Used for error-checking.

	// Send the new projection matrix to D3D
	if( FAILED( hr = pDirect3DDevice->SetTransform(D3DTS_PROJECTION, &projectionMatrix) ) )
	{
		POSTERR(hr);	// Unable to Set Transformation
		return;
	}

}

void	CDirect3DManager::Clear(int nRed, int nGreen, int nBlue, DWORD dwFlags,
									int nRectsToClear,	const D3DRECT * pRectsToClear)
{
	HRESULT	hr	=	0;	// Used for error-checking.

	// Clear Buffers
	if( FAILED( hr = pDirect3DDevice->Clear(nRectsToClear, pRectsToClear, dwFlags, D3DCOLOR_XRGB(nRed, nGreen, nBlue),1.0f, 0) ))
		POSTERR(hr);
	
	// Begin a new scene
	if( FAILED( hr = pDirect3DDevice->BeginScene() ))
		POSTERR(hr);
}

void	CDirect3DManager::Text(char * strText, int nX, int nY, int nRed, int nGreen, int nBlue, bool bShadow, DXM_FONT_SIZE eSize)
{
	// Create a rectangle in which to draw the text
	RECT	rTextArea = { nX, nY, 0, 0 };
	
	// Draw the text (no clipping)
	pFont->DrawText(NULL, strText, (int)strlen(strText), &rTextArea, DT_NOCLIP, D3DCOLOR_XRGB(nRed,nGreen,nBlue));

}

void	CDirect3DManager::BeginSprites()
{
	pCurrentSpriteMatrix = NULL;
	pSpriteInterface->Begin(D3DXSPRITE_ALPHABLEND);
}

void	CDirect3DManager::Sprite(LPDIRECT3DTEXTURE9 pTexture, D3DXMATRIX * pmSprite, D3DCOLOR dxColor,
									D3DXVECTOR3 * pvCenter, RECT * prSource)
{
	HRESULT hr = NULL;

	// Set the sprite's matrix
	pSpriteInterface->SetTransform(pmSprite);

	// Draw the mighty sprite
	if(FAILED(hr = pSpriteInterface->Draw(pTexture, prSource, pvCenter, NULL, dxColor)))
		POSTERR(hr);
}

void	CDirect3DManager::EndSprites()
{
	pSpriteInterface->End();
}


void	CDirect3DManager::Show()
{
	HRESULT	hr	=	0;	// Used for error-checking.

	// End the Scene
	if( FAILED( hr = pDirect3DDevice->EndScene() ))
		POSTERR(hr);

	// Present the buffer
	if( FAILED( hr = pDirect3DDevice->Present(0,0,0,0) ))
		POSTERR(hr);
}

bool	CDirect3DManager::Shutdown()
{
	/*******************/
	/* RELEASE OBJECTS */

	if(pDirect3DInterface)
		pDirect3DInterface->Release();

	if(pDirect3DDevice)
		pDirect3DDevice->Release();

	return true;
}

// The following is only included if the AlertManager is also being used.
#ifdef _ALERTMANAGER_H_

	bool	CDirect3DManager::ShowAlerts()
	{
		return true;
	}

#endif